package org.wzy.spring.framework.transaction.config;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 类似于 BeanDefinition, 主要是对 Aop 配置文件中体现的内容进行封装
 * 原因是: 目标代理对象的某个方法需要用自己实现的业务逻辑增强
 * <p>
 * 配置文件目的: 告诉 Spring, 哪些类的哪些方法需要增强，增强的内容是什么
 *
 * @author wzy_h
 * @version v_1.0
 * @date 2018/5/26 15:51
 * @since 1.8
 */
public class AopAutoProxyConfigurer {

    /**
     * 目标对象中需要增强的 Method 作为key
     * 需要增强的自定义代码内容作为 value
     */
    private Map<Method, Aspect> pointsMap = new HashMap<>();

    /**
     * 保存目标增强方法和切入点及通知方法之间的关联关系
     *
     * @param method       需要被增强的目标方法
     * @param aspect       切面对象, 如 LogAspect
     * @param pointsMethod 通知方法, 如 LogAspect 中的 before 和 after 方法
     * @author wzy_h
     * @date 2018/5/26 16:09
     * @since 1.8
     */
    public void put(Method method, Object aspect, Method[] pointsMethod) {
        this.pointsMap.put(method, new Aspect(aspect, pointsMethod));
    }

    /**
     * 获取目标增强方法所关联的切面对象及通知方法
     *
     * @param method 切面方法
     * @author wzy_h
     * @date 2018/5/26 16:08
     * @since 1.8
     */
    public Aspect get(Method method) {
        return this.pointsMap.get(method);
    }

    /**
     * 获取目标方法是否需要被增强
     *
     * @author wzy_h
     * @date 2018/5/26 16:11
     * @since 1.8
     */
    public boolean contains(Method method) {
        return this.pointsMap.containsKey(method);
    }

    /**
     * 内部类, 类似于 HandlerMapping, 主要用于封装自定义的用于增强目标方法的代码
     *
     * @author wzy_h
     * @version v_1.0
     * @date 2018/5/26 16:06
     * @since 1.8
     */
    public class Aspect {

        /**
         * 切面对象, 如 LogAspect
         */
        private Object aspect;

        /**
         * 用于增强目标方法的通知方法, 如 LogAspect 中的 before 和 after 方法
         */
        private Method[] points;

        Aspect(Object aspect, Method[] points) {
            this.aspect = aspect;
            this.points = points;
        }

        public Object getAspect() {
            return aspect;
        }

        public Method[] getPoints() {
            return points;
        }
    }
}
